import time
from sys import stdout
from math import exp, pi
from common import Common
#main configuration class
class Config:
###############################################################################
#basic configuration
###############################################################################
	debug = False # or True
	verbose = False #or debug or True
	allow_training = True
	allow_testing = True
	allow_imaging = False or True
	allow_imaging_heavy = False  or True
	allow_imaging_final = False  or True
	c = Common()
###############################################################################
#training configuration
###############################################################################
	#basics
	nna_npi = 4
	training_set_size = 50
	test_set_size = 50
	#architecture
	tau = 0.1
	eta = 0.75

	training_positive_window = 0.1
	training_negative_window =  0.06

	new = True

	terminal_weight_max = 1.0 / (nna_npi * 0.9)

	neighborhood_power = 0.39
	neighborhood_size = training_positive_window
	neighborhood_maxn = 20.0
	#training_max_slope =  training_positive_window / training_conjugate_distance
	nna_nit = 50
	synergy = 0.05
	def L(self, dt, m):
		#print m
		width = self.training_positive_window / m
		b = - self.training_negative_window
		#print width
		#b = -(width / (1 - width )) * self.training_negative_window
		#print 'learn',width, b
		c = 0
		#print (num+1) ** 0.5,'!'
		dw = self.eta * (1 - b) * exp(-((dt / width) ** 2)) + b
		return dw

	#data
	data_file = '../data/iris.data'
###############################################################################
#performance configuration
###############################################################################
	p = 10.0 ** 10 #precision
	ip = 0.1 ** 5
###############################################################################
#architecture
###############################################################################
	nna_hlayers = 0
	nna_nph = 0

	nna_npo = 3
	nu = 1.0									#membrane potential threshold
	reset_time = 0.5						 	#membrane potential decay time constant
	reset_potential = -0.5

	#terminals
	terminal_weight_min = 0.0
	terminal_delay_min = 0.0

	def architecture_to_str(self):
			out = str(self.nna_npi) + '->[' + str(self.nna_nph)
			out += 'x' + str(self.nna_hlayers) + ']->' + str(self.nna_npo)
			neurons = self.nna_hlayers * self.nna_nph
			neurons += self.nna_npi + self.nna_npo
			out += ' | neurons ' + str(neurons)
			synapses = 0
			if self.nna_nph and self.nna_hlayers:
				synapses += elf.nna_nph ** self.nna_hlayers
				synapses += self.nna_npi * self.nna_nph
				synapses += self.nna_npi * self.nna_npo
			else:
				synapses += self.nna_npi * self.nna_npo
			out += ' | synapses ' + str(synapses)
			return out

	def epsilon(self, dt, width, weight):								   	#spike-response function describing a standard PSP
		#if dt <= -width: return 0
		x = (dt + width) / width
		#return weight * x * exp(1 - x)
		return weight * exp(-((dt/width)**2))

	def ireset(self, dt):
		dw = self.reset_potential * exp(-dt / self.reset_time)
		return dw

###############################################################################
#graphics configuration
###############################################################################
	image_path = '../results/graphics/'
	image_extension = 'PNG'
	image_network_scale = 50.0
	image_data_scale = 2
	image_epsilon_scale = 4
###############################################################################
#log configuration
###############################################################################
	log_handle = None
	log_time_start = time.time()
	log_time = time.time()
	log_file = '../results/log.txt'

	def log(self, m, l = 3):
		if self.log_handle:
			message = {
						'1': lambda x: ' * ' * 20 + '\t' + x + '\t' + ' * ' * 20,
						'2': lambda x: "%2.3f %s" % (time.time() - self.log_time, x),
						'3': lambda x: '\t' + x
  					}[str(l)](m)
  			if l == '2':
  				self.log_time = time.time()
			self.log_handle.write(message + '\r\n');

	def percentage(self, i):
		percent = float(i) / (self.training_set_size + self.test_set_size)
		p = int(percent * 100)
		if p == 100:
			stdout.write('[ ok ]' + ' '*100)
		else:
			stdout.write('[%s%s]\r' % ('#' * p,' ' * (100 - p)))
		stdout.flush()

###############################################################################
#constructors & destructors
###############################################################################
	def __init__(self):
		self.log_handle = open(self.log_file, 'w')

	def __del__(self):
		self.log_handle.flush()
		self.log_handle.close()

	def __str__(self):
		return 'eta = %1.3f tpw = %1.3f tnw = %1.3f tw = %1.3f  nit=%d tau=%1.3f'%(self.eta, self.training_positive_window, self.training_negative_window, self.terminal_weight_max, self.nna_nit, self.tau)